package com.ben.chatroom.distribute;

import com.ben.chatroom.common.constants.ServerConstants;
import com.ben.chatroom.common.entity.ImNode;
import com.ben.chatroom.common.exception.BusinessException;
import com.ben.chatroom.common.util.JsonUtil;
import com.ben.chatroom.common.zk.CuratorZKclient;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.apache.curator.framework.CuratorFramework;
import org.apache.zookeeper.CreateMode;
import org.apache.zookeeper.data.Stat;
import org.springframework.util.StringUtils;

import java.util.List;

/**
 * @author huangyijun
 */
@Data
@Slf4j
public class ImWoker {

  private ImNode localNode;
  private boolean inited = false;
  private CuratorFramework client;
  private String pathRegistered;
  private static ImWoker singleInstance;


  public synchronized static ImWoker getInst() {
    if(singleInstance == null) {
      singleInstance = new ImWoker();
      singleInstance.localNode = new ImNode();
    }

    return singleInstance;
  }


  public void setLocalNode(String ip, int port) {
    if(localNode != null) {
      localNode.setHost(ip);
      localNode.setPort(port);
    }
  }

  /**
   * 创建临时节点
   */
  public synchronized void init() {
    if(!isInited()) {
      return;
    }

    if(client == null) {
      this.client = CuratorZKclient.getSingleton().getClient();
    }

    if(null == localNode) {
      localNode = new ImNode();
    }
    delteWhenHasNoChildren(ServerConstants.MAGIC_PATH);
    createParentIfNeed(ServerConstants.MAGIC_PATH);

    try {
      byte[] payload = JsonUtil.object2JsonBytes(localNode);

      pathRegistered = client.create()
                             .creatingParentsIfNeeded()
                             .withMode(CreateMode.EPHEMERAL_SEQUENTIAL)
                             .forPath(ServerConstants.PATH_PREFIX, payload);

      localNode.setId(getIdByPath(pathRegistered));
      log.info("本地节点，path={},id={}", pathRegistered, localNode.getId());
    }
    catch(Exception e) {
      log.error(e.getMessage());
    }


  }


  public void delteWhenHasNoChildren(String path) {
    int index = path.lastIndexOf("/");

    String parent = path.substring(0, index);
    boolean exist = isNodeExist(parent);

    if(exist) {
      List<String> children = getChildren(parent);
      if(null != children && children.isEmpty()) {
        delPath(parent);
      }
    }
  }

  public List<String> getChildren(String path) {
    try {
      return client.getChildren().forPath(path);
    }
    catch(Exception e) {
      throw new RuntimeException(e);
    }
  }

  /**
   * 创建父节点
   */
  public void createParentIfNeed(String path) {
    try {
      if(!isNodeExist(path)) {
        client.create()
              .creatingParentsIfNeeded()
              .withProtection()
              .withMode(CreateMode.PERSISTENT)
              .forPath(path);
      }
    }
    catch(Exception e) {
      log.error(e.getMessage());
    }

  }

  /**
   * 获取Im编号
   */
  public long getIdByPath(String path) {
    String sid = "";
    if(StringUtils.isEmpty(path)) {
      throw new BusinessException("节点路径为空。");
    }
    int index = path.lastIndexOf(ServerConstants.PATH_PREFIX);
    if(index > 0) {
      sid = path.substring(index + ServerConstants.PATH_PREFIX.length());
    }

    if(StringUtils.isEmpty(sid)) {
      throw new BusinessException("节点获取id失败");
    }

    return Long.parseLong(sid);
  }

  /**
   * 节点是否存在
   */
  public boolean isNodeExist(String zkPath) {
    try {
      Stat stat = client.checkExists().forPath(zkPath);
      if(null == stat) {
        log.info("节点不存在:{}", zkPath);
        return false;
      }
      else {
        log.info("节点存在，节点是:{}", stat);
        return true;
      }
    }
    catch(Exception e) {
      log.error(e.getMessage());
    }
    return false;
  }

  public void delPath(String path) {
    try {
      Void stat = client.delete().forPath(path);
    }
    catch(Exception e) {
      throw new RuntimeException(e);
    }

  }
}
